﻿using NoteHelper.IBusiness;
using NoteHelper.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace NoteHelper.Business.IbatisImpl
{
    public class AccountFlowManagerImpl : ManagerBase<Model.AccountFlow>, IAccountFlowManager
    {
        public DataTable GetAccountList()
        {
            string statementName = "QueryAccountList";
            var ht = new Hashtable();
            ht.Add("Discarded", false);
            return QueryForDataTable(statementName, ht);
        }

        public DataTable GetBizTypeList()
        {
            var table = new DataTable();
            table.Columns.Add("id", typeof(FlowType));
            table.Columns.Add("text", typeof(string));
            table.Rows.Add(new object[] { FlowType.FlowIn, "收入" });
            table.Rows.Add(new object[] { FlowType.FlowOut, "支出" });
            return table;
        }

        [Transaction]
        public override object Add(AccountFlow entity)
        {
            entity.HappenDate = entity.HappenDate.Date;
            entity.FlowSeq = GenerateFlowSeq(entity.AccountId, entity.HappenDate);
            var preEntity = GetPreFlow(entity.AccountId, entity.FlowSeq - 1);
            var preAmount = preEntity == null ? 0 : preEntity.LeftAmount;
            entity.LeftAmount = preAmount + entity.Amount * entity.BizType.GetHashCode();
            if (entity.BizType == FlowType.FlowOut && !string.IsNullOrEmpty(entity.ToAccountId))
            {
                // 转账
                entity.BusinessNo = string.Format("{0}-{1}", entity.AccountId, entity.FlowSeq);
                UpdateDiff(entity);
                var id = base.Add(entity);
                var toFlow = entity.CreateToFlow();
                toFlow.FlowSeq = GenerateFlowSeq(toFlow.AccountId, toFlow.HappenDate);
                preEntity = GetPreFlow(toFlow.AccountId, toFlow.FlowSeq - 1);
                preAmount = preEntity == null ? 0 : preEntity.LeftAmount;
                toFlow.LeftAmount = preAmount + toFlow.Amount * toFlow.BizType.GetHashCode();
                UpdateDiff(toFlow);
                base.Add(toFlow);
                return id;
            }
            else
            {
                // 普通收支
                UpdateDiff(entity);
                return base.Add(entity);
            }
        }

        private void UpdateDiff(AccountFlow entity)
        {
            var diff = entity.Amount * entity.BizType.GetHashCode();
            UpdateDiff(entity.AccountId, diff, entity.FlowSeq, 1);
        }

        private void UpdateDiff(string accountId, decimal diff, int flowSeq, int step)
        {
            var ht = new Hashtable();
            ht.Add("AccountId", accountId);
            ht.Add("Diff", diff);
            ht.Add("FlowSeq", flowSeq);
            ht.Add("Step", step);
            Mapper.Update("BatchUpdateDiff", ht);
        }

        [Transaction]
        public override int Delete(object id)
        {
            var entity = Get(id);
            if (!string.IsNullOrEmpty(entity.BusinessNo))
            {
                var ht = new Hashtable();
                ht.Add("BusinessNo", entity.BusinessNo);
                var lst = Mapper.QueryForList<AccountFlow>("QueryAccountFlowList", ht);
                int count = lst.Count;
                foreach (AccountFlow flow in lst)
                {
                    decimal diff = flow.Amount * flow.BizType.GetHashCode() * -1;
                    UpdateDiff(flow.AccountId, diff, flow.FlowSeq + 1, -1);
                    base.Delete(flow.Id);
                }
                return count;
            }
            else
            {
                decimal diff = entity.Amount * entity.BizType.GetHashCode() * -1;
                UpdateDiff(entity.AccountId, diff, entity.FlowSeq + 1, -1);
                return base.Delete(id);
            }
        }

        private int GenerateFlowSeq(string accountId, DateTime happenDate)
        {
            var ht = new Hashtable();
            ht.Add("AccountId", accountId);
            ht.Add("HappenDate", happenDate.Date.AddDays(1));
            string statementName = "GetAccountFlowSeq";
            LogRuntimeSql(statementName, ht);
            var obj = Mapper.QueryForObject(statementName, ht);
            int flowSeq = obj == null ? 0 : (int)obj;
            return flowSeq + 1;
        }

        public DataTable QueryAccountFlow(Hashtable ht)
        {
            var lst = QueryAccountFlowList(ht);
            return lst.ToDataTable("flows");
        }

        private IList<AccountFlow> QueryAccountFlowList(Hashtable ht)
        {
            string statementName = "QueryAccountFlowList";
            LogRuntimeSql(statementName, ht);
            var lst = Mapper.QueryPageList<AccountFlow>(statementName, ht, 0, 500);
            return lst;
        }

        /// <summary>
        /// 获取大于指定流水的记录
        /// </summary>
        /// <param name="accountId"></param>
        /// <param name="flowSeq"></param>
        /// <returns></returns>
        private IList<AccountFlow> GetAccountFlowList(string accountId, int flowSeq)
        {
            var ht = new Hashtable();
            ht.Add("AccountId", accountId);
            ht.Add("FromSeq", flowSeq); // 所有大于flowSeq的
            return QueryAccountFlowList(ht);
        }

        public AccountFlow UpdateFlow(object flowId, Hashtable rowData)
        {
            var entity = Get(flowId);
            if (string.IsNullOrEmpty(entity.ToAccountId) && entity.BusinessNo.Length > 1)
            {
                string notification = "不能在转入账号中对转账记录进行修改，只能在转出账号中修改！";
                throw new Exception(notification);
            }

            var newEntity = new AccountFlow();
            rowData.FillValueToEntity(newEntity);
            var newAmount = newEntity.Amount * newEntity.BizType.GetHashCode();
            if (newEntity.AccountId == entity.AccountId)
            {
                var preEntity = GetPreFlow(entity.AccountId, entity.FlowSeq - 1);
                var preAmount = preEntity == null ? 0 : preEntity.LeftAmount;
                var oldAmount = entity.Amount * entity.BizType.GetHashCode();
                var diff = newAmount - oldAmount;
                rowData.FillValueToEntity(entity);
                entity.LeftAmount = preAmount + newAmount;// 本期结存 = 上期结存 + 本期发生额
                Update(entity);
                UpdateDiff(entity.AccountId, diff, entity.FlowSeq + 1, 0);
                return entity;
            }
            else
            {
                Delete(flowId);
                Add(newEntity);
                return newEntity;
            }
        }

        /// <summary>
        /// 获取上一条记录
        /// </summary>
        /// <param name="accountId">账号ID</param>
        /// <param name="flowSeq">流水</param>
        /// <returns></returns>
        private AccountFlow GetPreFlow(string accountId, int flowSeq)
        {
            var ht = new Hashtable();
            ht.Add("AccountId", accountId);
            ht.Add("FlowSeq", flowSeq);
            var lst = QueryAccountFlowList(ht);
            return lst.FirstOrDefault();
        }
    }
}
